package de.unikoblenz.west.csxpoi;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import de.unikoblenz.west.csxpoi.R;

import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.EditText;

/**
 * The activity for logging in and signing up.
 */
public class LoginActivity extends Activity {

	/**
	 * the constant representing the logging in dialog
	 */
	private static final int LOGGING_IN_DIALOG = 1;

	/**
	 * Called when the activity is started.
	 */
	@Override
	protected void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);

		requestWindowFeature(Window.FEATURE_NO_TITLE);

		setContentView(R.layout.login);

		// Cancel button:

		final Button cancelButton = (Button) findViewById(R.id.cancel_button);
		cancelButton.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				finish();
			}
		});

		// Login button:

		final Button loginButton = (Button) findViewById(R.id.login_button);
		loginButton.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				String username = ((EditText) findViewById(R.id.username))
						.getText().toString();
				String password = ((EditText) findViewById(R.id.password))
						.getText().toString();
				if (!username.equals("")) {
					new AsyncLogin().execute(username, password);
				} else {
					setResult(RESULT_CANCELED);
					finish();
				}
			}
		});

		// Signup button:

		final Button signupButton = (Button) findViewById(R.id.signup_button);
		signupButton.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				if (findViewById(R.id.repeat_password_label).getVisibility() == View.GONE) {
					findViewById(R.id.repeat_password_label).setVisibility(
							View.VISIBLE);
					findViewById(R.id.repeat_password).setVisibility(
							View.VISIBLE);
					findViewById(R.id.login_button).setEnabled(false);
				} else {
					String username = ((EditText) findViewById(R.id.username))
							.getText().toString();
					String password = ((EditText) findViewById(R.id.password))
							.getText().toString();
					String repeatedPassword = ((EditText) findViewById(R.id.repeat_password))
							.getText().toString();
					if (!username.equals("")
							&& password.equals(repeatedPassword)) {
						new AsyncSignup().execute(username, password);
					} else {
						setResult(RESULT_CANCELED);
						finish();
					}
				}
			}
		});
	}

	/**
	 * Called when a dialog is shown.
	 */
	@Override
	protected Dialog onCreateDialog(int id) {
		switch (id) {
		case LOGGING_IN_DIALOG:
			ProgressDialog loggingInDialog = new ProgressDialog(this);
			loggingInDialog.setTitle(R.string.logging_in_dialog_title);
			loggingInDialog.setMessage(getResources().getString(
					R.string.please_wait_text));
			loggingInDialog.setIndeterminate(true);
			loggingInDialog.setCancelable(false);
			return loggingInDialog;
		}
		return super.onCreateDialog(id);
	}

	/**
	 * Asynchronously logs the user in.
	 */
	private class AsyncLogin extends AsyncTask<String, Void, String> {

		/**
		 * Called before the asynchronous login.
		 */
		@Override
		protected void onPreExecute() {
			showDialog(LOGGING_IN_DIALOG);
		}

		/**
		 * Called when starting the asynchronous login.
		 */
		@Override
		protected String doInBackground(String... args) {
			String username = args[0];
			String password = args[1];
			return requestUserId(username, password);
		}

		/**
		 * Called after the asynchronous login.
		 */
		@Override
		protected void onPostExecute(String userId) {
			dismissDialog(LOGGING_IN_DIALOG);
			Intent resultIntent = new Intent(LoginActivity.this,
					CsxPoiActivity.class);
			resultIntent.putExtra("userid", userId);
			setResult(RESULT_OK, resultIntent);
			finish();
		}
	}

	/**
	 * Parses the XML response from the user REST request.
	 */
	private class LoginSaxHandler extends DefaultHandler {

		/**
		 * the status of the response
		 */
		private String mStatus = "";

		/**
		 * the ID of the user
		 */
		private String mId = "";

		/**
		 * the characters of the current tag
		 */
		private String mCurrentCharacters = "";

		/**
		 * the constant for the user tag
		 */
		private static final String USER_TAG = "user";

		/**
		 * the constant for the id tag
		 */
		private static final String ID_TAG = "id";

		/**
		 * the constant for the status attribute
		 */
		private static final String STATUS_ATTRIBUTE = "status";

		/**
		 * Handles opening tags.
		 */
		@Override
		public void startElement(String uri, String localName, String qName,
				Attributes attributes) throws SAXException {
			if (localName.equals(USER_TAG)) {
				mStatus = attributes.getValue(STATUS_ATTRIBUTE);
			}
		}

		/**
		 * Handles closing tags.
		 */
		@Override
		public void endElement(String uri, String localName, String qName)
				throws SAXException {
			if (localName.equals(ID_TAG)) {
				mId = mCurrentCharacters;
			}
		}

		/**
		 * Handles characters of tags.
		 */
		@Override
		public void characters(char[] ch, int start, int length)
				throws SAXException {
			mCurrentCharacters = new String(ch, start, length);
		}

		/**
		 * Gets the ID of the user.
		 * 
		 * @return the ID of the user
		 */
		public String getUserId() {
			if (mStatus.equals("success"))
				return mId;
			return null;
		}
	}

	/**
	 * Asynchronously signes the user up.
	 */
	private class AsyncSignup extends AsyncTask<String, Void, String> {

		/**
		 * Called before the asynchonous signup.
		 */
		@Override
		protected void onPreExecute() {
			showDialog(LOGGING_IN_DIALOG);
		}

		/**
		 * Called when starting the asynchronous signup.
		 */
		@Override
		protected String doInBackground(String... args) {
			String username = args[0];
			String password = args[1];

			try {
				String urlString = Constants.REST_ADDRESS + "users"
						+ "?username=" + Encoder.urlEncode(username)
						+ "&password=" + Encoder.sha1Hash(password);
				HttpClient client = new DefaultHttpClient();
				HttpPost request = new HttpPost(urlString);
				HttpResponse response = client.execute(request);
				if (response.getStatusLine().getStatusCode() != 404) {
					// TODO: parse response (success/failure)
				} else {
					return null;
				}
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			} catch (ClientProtocolException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}

			return requestUserId(username, password);
		}

		/**
		 * Called after the asynchronous signup.
		 */
		@Override
		protected void onPostExecute(String userId) {
			dismissDialog(LOGGING_IN_DIALOG);
			Intent resultIntent = new Intent(LoginActivity.this,
					CsxPoiActivity.class);
			resultIntent.putExtra("userid", userId);
			setResult(RESULT_OK, resultIntent);
			finish();
		}
	}

	/**
	 * Requests the ID of the user with the specified username and password.
	 * 
	 * @param username
	 *            the username of the user
	 * @param password
	 *            the password of the user
	 * @return the ID of the user with the specified username and password
	 */
	private String requestUserId(String username, String password) {
		try {
			URL url = new URL(Constants.REST_ADDRESS + "users" + "/"
					+ Encoder.urlEncode(username) + "?password="
					+ Encoder.sha1Hash(password));
			SAXParserFactory spf = SAXParserFactory.newInstance();
			SAXParser sp = spf.newSAXParser();
			XMLReader xr = sp.getXMLReader();
			LoginSaxHandler loginSaxHandler = new LoginSaxHandler();
			xr.setContentHandler(loginSaxHandler);
			xr.parse(new InputSource(url.openStream()));
			String userId = loginSaxHandler.getUserId();
			if (userId != null && userId.equals(""))
				userId = null;
			return userId;
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

}
